Imports System
Imports System.Collections.Generic
Imports System.IO
Imports System.IO.Compression
Imports System.Text
''' <summary>
''' Implements a PDF stream object
''' </summary>
''' <remarks>A stream object consist of a dictionnary followed by zero or more bytes
''' bracketed between keywords "stream" and "endstream"</remarks>
Friend Class clsPdfStreamObject
#Region "Private members"
    Private _dictionnary As clsPdfDictionnary    'The dictionnary of the stream
    Private _streamObject As clsPdfBaseObject    'The stream base object
    Private _buffer() As Byte                   'The decoded stream
    Private Const _chunkSize As Integer = 65535
#End Region
#Region "Constructors"
    ''' <summary>
    ''' Create a new stream object
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub New()
        _dictionnary = New clsPdfDictionnary
        _streamObject = CreateStreamObject()
    End Sub
    ''' <summary>
    ''' Create a stream object from existing pair dictionnary and stream
    ''' </summary>
    ''' <param name="streamDict"></param>
    ''' <param name="streamObj"></param>
    ''' <remarks></remarks>
    Public Sub New(ByVal streamDict As clsPdfDictionnary, ByVal streamObj As clsPdfBaseObject)
        If streamObj.Type <> PdfObjectTypes.StreamObject Then
            Throw New Exception("Cannot create a stream object from an object type of " + streamObj.Type.ToString)
        End If
        _dictionnary = streamDict
        _streamObject = streamObj

        If Not _dictionnary.ContainsKey(PDF_SUBTYPE) Then
            'We decode the stream
            _decode()
        Else
            'If it is an image stream, we do not decode the stream
            _buffer = _streamObject.Value
        End If
    End Sub
#End Region
#Region "Public Properties"
    Public ReadOnly Property GetDecodedData As Byte()
        Get
            GetDecodedData = _buffer
        End Get
    End Property


    ''' <summary>
    ''' Gives access to the stream's dictionnary object
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property Dictionnary() As clsPdfDictionnary
        Get
            Dictionnary = _dictionnary
        End Get
    End Property
    ''' <summary>
    ''' Gives access to the stream base object
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property StreamObject() As clsPdfBaseObject
        Get
            StreamObject = _streamObject
        End Get
    End Property
    ''' <summary>
    ''' Get or set the stream filter's type
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property Filter() As PdfFilters
        Get
            If _dictionnary.ContainsKey(PDF_FILTER) Then
                Filter = _stringToFilterType(_dictionnary.Item(PDF_FILTER).GetString)
            Else
                Filter = PdfFilters.NoFilter
            End If
        End Get
        Set(ByVal value As PdfFilters)
            Dim s As String = _filterTypeToString(value)
            _dictionnary.Add(PDF_FILTER, CreateNameObject(s), True)
        End Set
    End Property
#End Region
#Region "Public Methods"
    ''' <summary>
    ''' Set the stream length dictionnary key
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub SetStreamLength()
        _dictionnary.Add(PDF_LENGTH, CreateNumericObject(_streamObject.Value.Length), True)
    End Sub
    ''' <summary>
    ''' Add a byte to the stream
    ''' </summary>
    ''' <param name="b"></param>
    ''' <remarks></remarks>
    Public Sub AddValue(ByVal b As Byte)
        _streamObject.AddValue(b)
    End Sub
#End Region
#Region "Private Methods"
    Private Sub _decode()
        Dim msOutput As New MemoryStream
        Dim stream As MemoryStream

        _buffer = Nothing
        Select Case Filter
            Case PdfFilters.FlateDecode
                Dim cbread As Integer
                stream = New MemoryStream(_streamObject.Value)

                Dim zip As New clsPDFDeflateStream(stream, _dictionnary)

                Dim abResult(_chunkSize) As Byte
                Do
                    cbread = zip.Read(abResult, 0, abResult.Length)
                    If cbread > 0 Then
                        msOutput.Write(abResult, 0, cbread)
                    End If
                Loop Until cbread = 0
                zip.Close()
                msOutput.Flush()
                If msOutput.Length > 0 Then
                    msOutput.Capacity = CInt(msOutput.Length)
                End If
                _buffer = msOutput.GetBuffer
            Case PdfFilters.NoFilter
                _buffer = _streamObject.Value
                'Case PdfFilters.LZWDecode
                '    Dim cbread As Integer
                '    stream = New MemoryStream(_streamObject.Value)
                '    'stream.ReadByte()
                '    'stream.ReadByte()

                '    Dim zip As New GZipStream(stream, CompressionMode.Decompress, True)

                '    Dim abResult(_chunkSize) As Byte
                '    Do
                '        cbread = zip.Read(abResult, 0, abResult.Length)
                '        If cbread > 0 Then
                '            msOutput.Write(abResult, 0, cbread)
                '        End If
                '    Loop Until cbread = 0
                '    zip.Close()
                '    msOutput.Flush()
                '    If msOutput.Length > 0 Then
                '        msOutput.Capacity = CInt(msOutput.Length)
                '    End If
                '    _buffer = msOutput.GetBuffer
            Case Else
                'Filter not supported in this version of pdflib
                Throw New Exception("Unsupported filter " + Filter.ToString)
        End Select
    End Sub
    Private Function _filterTypeToString(ByVal type As PdfFilters) As String
        Select Case type
            Case PdfFilters.ASCII85Decode
                _filterTypeToString = PDF_ASCII85DECODE
            Case PdfFilters.ASCIIHexDecode
                _filterTypeToString = PDF_ASCIIHEXDECODE
            Case PdfFilters.CCITTFAXDecode
                _filterTypeToString = PDF_CCITTFAXDECODE
            Case PdfFilters.DCTDecode
                _filterTypeToString = PDF_DCTDECODE
            Case PdfFilters.JBIG2Decode
                _filterTypeToString = PDF_JBIG2DECODE
            Case PdfFilters.JPXDecode
                _filterTypeToString = PDF_JPXDECODE
            Case PdfFilters.LZWDecode
                _filterTypeToString = PDF_LZWDECODE
            Case PdfFilters.RunLengthDecode
                _filterTypeToString = PDF_RUNLENGTHDECODE
            Case PdfFilters.FlateDecode
                _filterTypeToString = PDF_FLATEDECODE
            Case Else
                _filterTypeToString = ""
        End Select
    End Function
    Private Function _stringToFilterType(ByVal type As String) As PdfFilters
        Select Case type
            Case PDF_ASCII85DECODE
                _stringToFilterType = PdfFilters.ASCII85Decode
            Case PDF_ASCIIHEXDECODE
                _stringToFilterType = PdfFilters.ASCIIHexDecode
            Case PDF_CCITTFAXDECODE
                _stringToFilterType = PdfFilters.CCITTFAXDecode
            Case PDF_DCTDECODE
                _stringToFilterType = PdfFilters.DCTDecode
            Case PDF_JBIG2DECODE
                _stringToFilterType = PdfFilters.JBIG2Decode
            Case PDF_JPXDECODE
                _stringToFilterType = PdfFilters.JBIG2Decode
            Case PDF_LZWDECODE
                _stringToFilterType = PdfFilters.LZWDecode
            Case PDF_RUNLENGTHDECODE
                _stringToFilterType = PdfFilters.RunLengthDecode
            Case PDF_FLATEDECODE
                _stringToFilterType = PdfFilters.FlateDecode
            Case Else
                _stringToFilterType = PdfFilters.UnknownFilter
        End Select
    End Function
#End Region
End Class